// 用于检查项得分的公共方法
import { isObject } from '@/utils'
const isString = str => typeof str === 'string'

/**
 * 判断得分等级
 * @param {String} levelStdd 等级标准
 * @param {String | Number} scoreNum 数值得分
 * @returns {String}
 * @example judgeScoreLevel('[{"max":"80","result":"C"},{"min":"80","max":"90","result":"B"},{"min":"90","result":"A"}]', 85) // 'B'
 */
export const judgeScoreLevel = (levelStdd, scoreNum) => {
  if (!levelStdd || scoreNum === '' || isNaN(+scoreNum)) return ''

  const num = +scoreNum || 0
  let stds = []
  try {
    stds = JSON.parse(levelStdd)
    if (!Array.isArray(stds)) return ''
  } catch (err) {
    console.error('解析等级标准失败', err)
    return ''
  }

  for (const std of stds) {
    const gteMin = typeof std.min === 'undefined' ? true : num >= std.min
    const ltMax = typeof std.max === 'undefined' ? true : num < std.max
    if (gteMin && ltMax) return std.result
  }
  return ''
}

/**
 * 判断得分结果(优秀/合格/不合格)
 * @param {String} resultStdd 合格标准
 * @param {String} enumVal 枚举值
 * @returns {String}
 * @example judgeScoreResult('[{"level":"A","result":"EXCELLENT"},{"level":"B","result":"VALID"},{"level":"C","result":"UNVALID"}]', 'B') // 'VALID'
 */
export const judgeScoreResult = (resultStdd, enumVal = '') => {
  if (!resultStdd) return ''

  let stds = []
  try {
    stds = JSON.parse(resultStdd)
    if (!Array.isArray(stds)) return ''
  } catch (err) {
    console.error('解析合格标准失败', err)
    return ''
  }

  for (const std of stds) {
    if (std.level === enumVal) return std.result
  }
  return ''
}

/**
 * 根据输入值匹配到规则，返回该项 result 值。
 * expResult 为 true 时返回 exp 的执行结果
 * @param {Object} opt
 * @param {Array<{
 *  result: String,
 *  eq?: String | Number,
 *  in?: String | String[] | Number[],
 *  min?: Number,
 *  max?: Number,
 *  formula?: String,
 *  exp?: String,
 *  expResult?: Boolean}>
 *  | String
 * } opt.rule 规则配置。数组或 JSON 字符串
 * @param {String} [opt.type='string'] 数据类型。可选值: 'string', 'number', 'object'
 * @param {String | Number | Object} opt.value 输入值
 * @returns {String | any}
 */
export const matchingRule = opt => {
  // 判断有效规则
  if (!opt?.rule) return ''
  let rules = opt.rule
  if (isString(rules)) {
    try {
      rules = JSON.parse(rules)
    } catch (err) {
      console.error('解析规则失败', err)
      return ''
    }
  }
  if (!Array.isArray(rules)) return ''

  // 判断有效值
  const valType = opt.type || 'string'
  let value = opt.value || ''
  if (valType === 'string') {
    if (!isString(value)) return ''
  } else if (valType === 'number') {
    if (isNaN(+opt.value)) return ''
    value = +opt.value || 0
  } else if (valType === 'object') {
    // 用于 exp 表达式变量运算
    if (!isObject(value)) return ''
  } else return ''

  for (const rule of rules) {
    // 每项规则需为对象
    if (!isObject(rule)) return ''
    if (rule.expResult) return parseRuleExp(rule.exp, value)
    if (parseRule(rule, value, valType)) return rule.result
  }
  return ''
}

const parseRule = (rule, value, valType) => {
  const hasProp = k => Object.prototype.hasOwnProperty.call(rule, k)

  if (hasProp('exp') || valType === 'object') return parseRuleExp(rule.exp, value)

  if (hasProp('eq')) return rule.eq === value

  if (hasProp('in')) {
    if (Array.isArray(rule.in)) return rule.in.includes(value)
    if (!isString(rule.in)) return
    const list = rule.in.split(',').filter(i => i)
    if (valType === 'number') return list.map(i => +i).includes(value)
    return list.includes(value)
  }

  if (hasProp('min') || hasProp('max')) {
    if (valType !== 'number') return
    const gteMin = typeof rule.min === 'undefined' ? true : value >= rule.min
    const ltMax = typeof rule.max === 'undefined' ? true : value < rule.max
    return gteMin && ltMax
  }

  if (hasProp('formula')) {
    const str = rule.formula
    if (!isString(str)) return

    if (str.includes('>=')) return value >= +str.split('>=')[1]
    if (str.includes('<=')) return value <= +str.split('<=')[1]
    if (str.includes('>')) return value > +str.split('>')[1]
    if (str.includes('<')) return value < +str.split('<')[1]

    if (str.includes('!=')) {
      const list = (str.split('!=')[1] || '').split(',').filter(i => i)
      if (valType === 'number') return !list.map(i => +i).includes(value)
      return !list.includes(value)
    }

    if (!str.includes('=')) return
    const list = (str.split('=')[1] || '').split(',').filter(i => i)
    if (valType === 'number') return list.map(i => +i).includes(value)
    return list.includes(value)
  }
}

/**
 * 执行表达式，返回结果
 * @param {String} exp JS表达式
 * @param {Object} obj 含多个输入值的对象
 */
const parseRuleExp = (exp, obj) => {
  try {
    if (!isString(exp) || !isObject(obj)) return ''
    exp = exp.replace(/\$/g, '$.')
    obj = JSON.stringify(obj)
    return Function(`'use strict';const $=${obj};return (${exp})`)()
  } catch (err) {
    // console.error('exp config err', err)
    return ''
  }
}
